/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.upf.grupE.impl;

import edu.upf.grupE.Listener;
import edu.upf.grupE.interftest.EventListenerImpl;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.NotFilter;
import org.jivesoftware.smack.filter.OrFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.muc.MultiUserChat;

/**
 *
 * @author Madhava Carrillo <madhava at me.com>
 */
public final class IM {
    /*Declaration of variables*/

    private XMPPConnection con = null;
    private MultiUserChat chat = null;
    protected EventListenerImpl el;

    /**
     * Creates the object and gets a printable textarea
     * @param texta
     */
    public IM(final EventListenerImpl el) {
        this.el = el;
    }

    /**
     *This method disconnects our aplication from gtalk
     */
    public void logout() {
        if (con != null) {
            con.disconnect();

        }
        el.setOffline();
    }

    /**
     * This method recieves two strings and creates a Message with them. It sets
     * the valor of the PacketID to PacketChatId, so when the listener receives
     * this packet, it will be able to distinguish that inside it there is a
     * chat message and operate with it. It also sets the destination adress
     * (which is the first string received as argument, and next sets the body
     * of the message (2nd string argument). It also adds an object wich will be
     * the date, so we will be able to know on reception when does the message
     * has been sent. After all the method calls the Send method do definitively
     * send the message.
     * @param rx The receiver of the message
     * @param msgstr The text to send
     */
    public void sendChat(final String rx, final String msgstr) {
        final Message msg = new Message();
        msg.setPacketID(Config.PACKETCHATID);
        msg.setTo(rx);
        msg.setBody(msgstr);
        msg.setProperty("fecha", new Date());
        send(msg);
    }

    /**
     * This method only gets the message and sends it. It also catches if there
     * have been any XMPPException
     * @param msg The Message to send
     */
    public void send(final Message msg) {
        try {
            chat.sendMessage(msg);
        } catch (XMPPException ex) {
            Logger.getLogger(IM.class.getName()).log(Level.SEVERE, null, ex);
            ex.printStackTrace();
        }
    }

    public Vector<RosterEntry> getOnlineContacts() {
        Vector<RosterEntry> contacts = new Vector<RosterEntry>();
        Roster roster = con.getRoster();
        //give time to retrieve information from the server

        for (Iterator<RosterEntry> i = roster.getEntries().iterator(); i.hasNext();) {

            RosterEntry re = (RosterEntry) i.next();
            Presence p = roster.getPresence(re.getUser());

            String status = p.getStatus();
            if (p.isAvailable()) {
                contacts.add(re);
            }
        }
        return contacts;
    }

    public Vector<RosterEntry> getIlusionOnlineContacts() {
        Vector<RosterEntry> contacts = new Vector<RosterEntry>();
        Roster roster = con.getRoster();
        //give time to retrieve information from the server

        for (Iterator<RosterEntry> i = roster.getEntries().iterator(); i.hasNext();) {

            RosterEntry re = (RosterEntry) i.next();
            Presence p = roster.getPresence(re.getUser());

            String status = p.getStatus();
            if (p.isAvailable() && (status != null)) {
                if (status.equalsIgnoreCase(Config.PRECENSE)) {
                    contacts.add(re);
                }
            }
        }
        return contacts;
    }

    /**
     * It's obvious to see what does this method do: it does the login with the
     * gtalk server and returns true if the connection has been done correctly or false
     * if there has been some Exception.
     * To do this we first have to do a new ConnectionConfiguration to define how
     * we will do the connection with gtalk. Then we create an XMPPConnectio using the
     * ConnectionConfiguranion values, then we connect and we do the login to the gmail account.
     * after that we print on the terminal our user name and we set result to true.
     * @param aLogin LoginName
     * @param aPassword Password
     * @param resource Resource
     * @return True when the conenction is succesfull
     */
    public boolean login(final String aLogin, final String aPassword, final String resource) {
        boolean result;
        try {


            PacketFilter filter7 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.PACKETSEARCHPROFILEID));
            Listener listener7 = new SearchProfileListener(this);

            PacketFilter filter8 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.PACKETSEARCHRESULTID));
            Listener listener8 = new searchResultListener(this);

            PacketFilter filter9 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.PACKETPICRESULT));
            Listener listener9 = new DownloadResultListener(this);

            PacketFilter filter5 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.PACKETPICREQUEST));
            Listener listener5 = new DownloadPictureListener(this);


            PacketFilter filter6 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.VIDEOREQUEST));
            Listener listener6 = new VideoRequestListener(this);

            PacketFilter filter2 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.RESPONSEVIDEOREQUEST));
            Listener listener2 = new VideoResponseListener(this);

            PacketFilter filter3 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.PACKETLISTVIDEOSRESULTID));
            Listener listener3 = new VideoListResponseListener(this);

            PacketFilter filter4 = new AndFilter(new PacketTypeFilter(Message.class), new PacketIDFilter(Config.PACKETLISTVIDEOSREQUESTID));
            Listener listener4 = new VideoListListener(this);

            PacketFilter filter = new NotFilter(
                    new OrFilter(
                    new OrFilter(
                    new OrFilter(
                    filter2,
                    filter3),
                    new OrFilter(
                    filter4,
                    filter5)),
                    new OrFilter(
                    new OrFilter(
                    filter6,
                    filter7),
                    new OrFilter(
                    filter8,
                    filter9))));


            Listener listener = new ChatListener(this);

            ConnectionConfiguration config = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com");
            config.setSASLAuthenticationEnabled(true);
            config.setReconnectionAllowed(true);
            con = new XMPPConnection(config);
            con.connect();
            con.login(aLogin, aPassword, resource);

            changePresence(Config.PRECENSE);
            chat = new MultiUserChat(con, aLogin + "'s Chat");
            System.out.println(con.getUser());
            result = true;

            addListener(listener, filter);
            addListener(listener2, filter2);
            addListener(listener3, filter3);
            addListener(listener4, filter4);
            addListener(listener5, filter5);
            addListener(listener6, filter6);
            addListener(listener7, filter7);
            addListener(listener8, filter8);
            addListener(listener9, filter9);


            Roster roster = con.getRoster();
            //give time to retrieve information from the server

            roster.addRosterListener(new RosterListener() {
                // Ignored events public void entriesAdded(Collection<String> addresses) {}

                public void entriesDeleted(Collection<String> addresses) {
                    el.actualizeUserList();
                }

                public void entriesUpdated(Collection<String> addresses) {
                    el.actualizeUserList();
                }

                public void presenceChanged(Presence presence) {

                    System.out.println("Presence changed: " + presence.getFrom() + " " + presence);
                    el.actualizeUserList();
                }

                public void entriesAdded(Collection<String> arg0) {
                    el.actualizeUserList();
                }
            });



        } catch (Throwable ex) {
            ex.printStackTrace();
            result = false;
            el.setLoginMsg("Error conecting to server.");
        }
        return result;
    }

    /**
     * We do only receive messages from users connected to the Ilusio Application, so we fix
     * a presence and we only print messages on which the presence is "IlusioVfG"
     * @param rx The origin
     * @param msg The message to show
     */
//    public void addText(final String rx, final String msg) {
//        Roster roster = con.getRoster();
//        Presence p = roster.getPresence(rx);
//        if (p.getStatus().equalsIgnoreCase(Config.PRECENSE)) {
//            ta.append(rx);
//            ta.append(" - ");
//            ta.append(msg);
//            ta.append("\n");
//        }
//    }
    /**
     * Change my  status
     * @param presencestr
     */
    public void changePresence(final String presencestr) {
        Presence presence = new Presence(Presence.Type.available);
        presence.setStatus(presencestr);
        con.sendPacket(presence);
    }

    /**
     * To add a new listener to the connection.
     * @param list
     * @param filter
     */
    public void addListener(final Listener list, final PacketFilter filter) {
        con.createPacketCollector(filter);
        con.addPacketListener(list, filter);
    }

    /**
     *
     * @param nick
     */
    public void createAndJoinRoom(final String nick) {
        MultiUserChat muc = new MultiUserChat(con, "ilusionDFGGG");
        try {
            muc.create(nick);
            muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
        } catch (XMPPException ex) {
            Logger.getLogger(IM.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Ya existe!");

        }
        try {
            muc.join(nick);
        } catch (XMPPException ex) {
            Logger.getLogger(IM.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("La creamos");
        }
    }

    public void requestPicture(final String user, final String pictureId) {
        System.out.println("Pedimos la foto " + pictureId + " a " + user);
        Message req = new Message();
        req.setPacketID(Config.PACKETPICREQUEST);
        req.setTo(user);
        req.setBody(pictureId);

        send(req);
    }

    public void requestVideo(final String user, final String ip, final String port, final String videoid) {
        Message req = new Message();
        req.setPacketID(Config.VIDEOREQUEST);
        req.setTo(user);
        req.setProperty("ip", ip);
        req.setProperty("port", port);
        req.setProperty("videoid", videoid);
        send(req);
    }

    public void responseVideo(final String user, final String ip, final String port) {
        Message req = new Message();
        req.setPacketID(Config.RESPONSEVIDEOREQUEST);
        req.setTo(user);
        req.setProperty("ip", ip);
        req.setProperty("port", port);
        send(req);
    }

    /**
     * This method is similar to the sendChat one, but the diference between them
     * is that this one does not contain any String in the Message body and it contains
     * a Picture object set as Property. It also checks that the destination address has presence
     * on the roster. The ID of this type os messages is PacketSearchProfileID
     * because this type of packets are thougt to carry the searching petition to the other
     * users of the application. After filling the message, the method Send is called.
     *
     * @param searchPic Picture descrption to search
     */
    public void sendSearchProfile(final searchProfile searchPic) {
        Roster roster = con.getRoster();

        for (Iterator<RosterEntry> i = roster.getEntries().iterator(); i.hasNext();) {
            RosterEntry re = (RosterEntry) i.next();
            Presence p = roster.getPresence(re.getUser());
            String status = p.getStatus();

            if (p.isAvailable() && (status != null)) {
                if (status.equalsIgnoreCase(Config.PRECENSE)) {
                    Message msg = new Message();
                    System.out.println("Enviando busqueda a " + re.getUser());
                    msg.setPacketID(Config.PACKETSEARCHPROFILEID);
                    msg.setProperty("searchPic", searchPic);
                    msg.setTo(re.getUser());
                    send(msg);
                }
            }
        }
    }

    public void sendVideoList(String to) {
        Message msg = new Message();

        msg.setPacketID(Config.PACKETLISTVIDEOSREQUESTID);
        msg.setTo(to);
        msg.setBody("proba_buskedavideorebut");
        send(msg);
        System.out.println("Peticion de lista de videos a " + to);
    }
}
